#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "serial/mycommandgenerator.h"
#include <QDebug>
#include "serial/myserialwidget.h"
#include <windows.h>
#include <QTimer>
#include <QTime>

#define MYDebug() do{qDebug() << __FILE__ << "{" << __func__ << ":" << __LINE__ << "}";}while(0)

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , frame_index(0)
{
    ui->setupUi(this);

    setupUI();

    timer = new QTimer(this);
    auto conn2 = QObject::connect(timer, &QTimer::timeout, this, &MainWindow::slot_loop_send);

    ui->pushButton_3->setEnabled(false);
    ui->pushButton->setEnabled(true);
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_pushButton_clicked()
{
    frame_index = 0;
    ui->labe_frame_count->setText("0");
    timer->start(40);
    ui->pushButton_3->setEnabled(true);
    ui->pushButton->setEnabled(false);
    ui->comboBox_datatype->setEnabled(false);
}

void MainWindow::on_pushButton_3_clicked()
{
    timer->stop();
    ui->pushButton_3->setEnabled(false);
    ui->pushButton->setEnabled(true);
    ui->comboBox_datatype->setEnabled(true);
}


typedef struct framehead {
    uint32_t tag;                    // tag: "wyld" hex is "77 79 6C 64", in 32bit word "0x646c7977".
    uint16_t width;                  // resolution width
    uint16_t height;                 // resolution height
    uint32_t frame_size;             // frame size, in bytes.
    uint16_t line_size;              // line size, in bytes.
    uint16_t data_type;              // stream data type: 0: peak; 1: distance; 2: depth; 3: pointcloud
    uint32_t frame_idx;              // frame index(counter++).
    uint32_t reserved5;              // last_frame_crc?
    uint32_t reserved6;              // reserved
    uint32_t version;                // version
} wy6005_frame_head_t;

enum STREAM_DATA_TYPE_EMUM {
    STREAM_DATA_TYPE_PEAK_DATA = 0,             // peak data format: peakdata*width + gray*width. peak format int16_t, gray data format uint16_t.
    STREAM_DATA_TYPE_DISTANCE_DATA,             // distance data format: distdata*width + gray*width. distance format int16_t, gray data format uint16_t.
    STREAM_DATA_TYPE_DEPTH_DATA,                // depth data format: depthdata*width + gray*width. depth format int16_t, gray data format uint16_t.
    STREAM_DATA_TYPE_POINT_DATA,                // point data format: (x,y,z,gray)*width. (x,y,z)format int16_t, gray data format uint16_t.
    STREAM_DATA_TYPE_DEBUG_DATA,
};

void MainWindow::slot_loop_send()
{
    qDebug() << QTime::currentTime() << "send a frame";
    MyCommand cmd;
    cmd.mode = SERIAL_MODE::SERIAL_MODE_ASYNCHRONOUS;

    int data_type = ui->comboBox_datatype->currentIndex();

    typedef int (*PickdataFunc)(MyCommand &cmd, int size, int);
    int data_count ,line_size,frame_size;
    int gbytefactor = ui->radioButton_32bits->isChecked() ? 2 : 1; // gray data byte factor by uint16_t

    PickdataFunc pickdata ;

    if (data_type == 3)
    {
        data_count = 64; // only 16bits point_data
        line_size = 64 * 2 * 4; // 64 * 2(16bits) * (1x + 1y + 1z + 1gray)
        frame_size = line_size * 8;

        pickdata = &MyCommandGenerator::pointdata;
    }

    else if (data_type == 4) // peak data + debug data
    {
        data_count = 48; // only 16bits
        line_size = 64 * 2 * 2 + 64 * 2; // 64 * 2(16bits) * (1pcd + 1gray) + 64 * (1 high_histogram + 1 low_histogram)
        frame_size = line_size * 8;

        pickdata = &MyCommandGenerator::debugdata;
    }
    else {
        data_count = 32 * gbytefactor;
        line_size = 64 * 2 * (gbytefactor + 1) ;
        frame_size = line_size * 8;

        pickdata = &MyCommandGenerator::peakdata;
    }

    uint8_t head_data[32] = {0x77, 0x79, 0x6C, 0x64, 0x40, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xD3, 0x00, 0x00, 0x00, 0x12, 0x34, 0xAB, 0xCD, 0x12, 0x34, 0xAB, 0xCD, 0x12, 0x34, 0xAB, 0xCD};
    uint8_t *head = head_data;
    wy6005_frame_head_t *frame_head = (wy6005_frame_head_t *)head;

    frame_head->width = 64;
    frame_head->height = 8;
    frame_head->data_type = data_type;
    frame_head->frame_idx = frame_index;
    frame_head->frame_size = frame_size;
    frame_head->line_size = line_size;

    QByteArray data((char*)(&head_data), sizeof(head_data));
    ui->mySerialWidget->send(data);
    // qDebug() << "head"  << data.toHex(' ');

    for (int i=0; i<data_count;i++) {
        pickdata(cmd, data_count, gbytefactor);
        ui->mySerialWidget->sendCmd(cmd, nullptr);
    }

    frame_index++;
    MyCommandGenerator::canfdToggle();

    ui->labe_frame_count->setText(QString::number(frame_index));
}

void MainWindow::handleSerialStateChanged(bool connected)
{
    MYDebug() ;

    ui->pushButton->setEnabled(connected);
}

void MainWindow::handleSerialDataReaded(QByteArray &data)
{
    MYDebug() ;
    qDebug() << "async recv2 :" << data.toHex(' ');
    qDebug() << "async recv2 :" << data;

    char *rawdata = data.data();
    if ((rawdata[0] == 'A'||rawdata[0] == 'a')&&(rawdata[1] == 'T'||rawdata[0] == 't')) {
        QString cmd(data);
        if (cmd.toUpper().startsWith(QString("AT+SPAD_TRIG_ONE_FRAME=1"))) {
            slot_loop_send();
            return;
        }
    }

}

void MainWindow::setupUI()
{
    handleSerialStateChanged(false);

    QObject::connect(ui->mySerialWidget, &MySerialWidget::sign_stateChanged, this, &MainWindow::handleSerialStateChanged);
    QObject::connect(ui->mySerialWidget, &MySerialWidget::sign_dataReaded, this, &MainWindow::handleSerialDataReaded);
}
